<?php
/*                                                                        *
 * This script is part of the TYPO3 project - inspiring people to share!  *
 *                                                                        *
 * TYPO3 is free software; you can redistribute it and/or modify it under *
 * the terms of the GNU General Public License version 2 as published by  *
 * the Free Software Foundation.                                          *
 *                                                                        *
 * This script is distributed in the hope that it will be useful, but     *
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General      *
 * Public License for more details.                                       *
 *
 * $Id: Tx_Formhandler_Controller_Form.php 85377 2014-05-23 07:55:07Z reinhardfuehricht $
 *                                                                        */

/**
 * Default controller for Formhandler
 *
 * @author	Reinhard Führicht <rf@typoheads.at>
 */
class Tx_Formhandler_Controller_Form extends Tx_Formhandler_AbstractController {

	/**
	 * The current GET/POST parameters of the form
	 *
	 * @access protected
	 * @var array
	 */
	protected $gp;

	/**
	 * Contains all errors occurred while validation
	 *
	 * @access protected
	 * @var array
	 */
	protected $errors;

	/**
	 * Holds the prefix value of all parameters of this form.
	 *
	 * @access protected
	 * @var string
	 */
	protected $formValuesPrefix;

	/**
	 * The template file to be used. Only if template file was defined via plugin record
	 *
	 * @access protected
	 * @var string
	 */
	protected $templateFile;

	/**
	 * Array of configured translation files
	 *
	 * @access protected
	 * @var array
	 */
	protected $langFiles;

	/**
	 * Flag indicating if the form got submitted
	 *
	 * @access protected
	 * @var boolean
	 */
	protected $submitted;

	/**
	 * The settings array
	 *
	 * @access protected
	 * @var array
	 */
	protected $settings;

	/**
	 * Flag indicating if debug mode is on
	 *
	 * @access protected
	 * @var boolean
	 */
	protected $debugMode;

	/**
	 * The view object
	 *
	 * @access protected
	 * @var misc
	 */
	protected $view;

	/**
	 * The current step of the form
	 *
	 * @access protected
	 * @var integer
	 */
	protected $currentStep;

	/**
	 * The last step of the form
	 *
	 * @access protected
	 * @var integer
	 */
	protected $lastStep;

	/**
	 * Total steps of the form
	 *
	 * @access protected
	 * @var integer
	 */
	protected $totalSteps;

	/**
	 * Flag indicating if form is finished (no more steps)
	 *
	 * @access protected
	 * @var boolean
	 */
	protected $finished;

	/**
	 * Main method of the form handler.
	 *
	 * @return rendered view
	 */
	public function process() {
		$this->init();
		$this->storeFileNamesInGP();
		$this->processFileRemoval();

		$action = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('action');
		if ($this->globals->getFormValuesPrefix()) {
			$temp = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP($this->globals->getFormValuesPrefix());
			$action = $temp['action'];
		}
		if ($action) {

			//read template file
			$this->templateFile = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings);
			$this->globals->setTemplateCode($this->templateFile);
			$this->langFiles = $this->utilityFuncs->readLanguageFiles($this->langFiles, $this->settings);
			$this->globals->setLangFiles($this->langFiles);

			$this->view->setLangFiles($this->langFiles);
			$this->view->setSettings($this->settings);

			//reset the template because step had probably been decreased
			$this->setViewSubpart($this->currentStep);
			$content = $this->processAction($action);
			if(strlen(trim($content)) > 0) {
				return $content;
			}
		}

		if (!$this->submitted) {
			return $this->processNotSubmitted();
		} else {
			return $this->processSubmitted();
		}
	}

	/**
	 * Internal method to process an action link generated by Finisher_SubmittedOK.
	 * This is used to generate a print version or files using submitted form data.
	 *
	 * @param string $action The action to perform. This must equal "show" for a print version or an action defined in the config of Finisher_SubmittedOK
	 * @return string The generated content
	 */
	protected function processAction($action) {
		$content = '';
		$gp = $_GET;
		if ($this->globals->getFormValuesPrefix()) {
			$gp = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP($this->globals->getFormValuesPrefix());
		}
		if (is_array($this->settings['finishers.'])) {
			$finisherConf = array();
			foreach ($this->settings['finishers.'] as $key => $config) {
				if (strpos($key, '.') !== FALSE) {
					$className = $this->utilityFuncs->getPreparedClassName($config);
					if ($className === 'Tx_Formhandler_Finisher_SubmittedOK' && is_array($config['config.'])) {
						$finisherConf = $config['config.'];
					}
				}
			}
			$params = array();
			$tstamp = intval($gp['tstamp']);
			$hash = $GLOBALS['TYPO3_DB']->fullQuoteStr($gp['hash'], 'tx_formhandler_log');
			if ($tstamp && strpos($hash, ' ') === FALSE) {
				$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('params', 'tx_formhandler_log', 'tstamp=' . $tstamp . ' AND unique_hash=' . $hash);
				if ($res && $GLOBALS['TYPO3_DB']->sql_num_rows($res) === 1) {
					$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
					$GLOBALS['TYPO3_DB']->sql_free_result($res);
					$params = unserialize($row['params']);
				}
			}
			if ($finisherConf['actions.'][$action . '.'] && !empty($params) && intval($this->utilityFuncs->getSingle($finisherConf['actions.'][$action . '.']['config.'], 'returns')) !== 1) {

				$class = $this->utilityFuncs->getPreparedClassName($finisherConf['actions.'][$action . '.']);
				if ($class) {
					$object = $this->componentManager->getComponent($class);
					$object->init($params, $finisherConf['actions.'][$action . '.']['config.']);
					$object->process();
				}
			} elseif($action === 'show') {

				//"show" makes it possible that Finisher_SubmittedOK show its output again
				$class = 'Tx_Formhandler_Finisher_SubmittedOK';
				$object = $this->componentManager->getComponent($class);
				unset($finisherConf['actions.']);
				$object->init($params, $finisherConf);
				$content = $object->process();
			} elseif(intval($this->utilityFuncs->getSingle($finisherConf['actions.'][$action . '.']['config.'], 'returns')) === 1) {
				$class = $this->utilityFuncs->getPreparedClassName($finisherConf['actions.'][$action . '.']);
				if ($class) {

					//Makes it possible to make your own Generator class show output
					$object = $this->componentManager->getComponent($class);
					$object->init($params, $finisherConf['actions.'][$action . '.']['config.']);
					$content = $object->process();
				} else {

					//Makes it possible that Finisher_SubmittedOK show its output again
					$class = 'Tx_Formhandler_Finisher_SubmittedOK';
					$object = $this->componentManager->getComponent($class);
					unset($finisherConf['actions.']);
					$object->init($params, $finisherConf);
					$content = $object->process();
				}
			}
		}
		return $content;
	}

	/**
	 * Process the form if the user clicked submit.
	 *
	 * @return string The generated content
	 */
	protected function processSubmitted() {

		/*
		 * Step may have been set to the next step already.
		 * Set the settings back to the one of the previous step 
		 * to run the right interceptors and validators.
		 */
		if ($this->currentStep > $this->lastStep) {
			$this->loadSettingsForStep($this->lastStep);
		} else {
			$this->loadSettingsForStep($this->currentStep);
		}

		$this->parseConditions();
		
		if ($this->currentStep > $this->lastStep) {
			$this->loadSettingsForStep($this->lastStep);
		} else {
			$this->loadSettingsForStep($this->currentStep);
		}

		//run init interceptors
		$this->addFormhandlerClass($this->settings['initInterceptors.'], 'Interceptor_Filtreatment');
		$output = $this->runClasses($this->settings['initInterceptors.']);
		if (strlen($output) > 0) {
			return $output;
		}

		//Search for completely unchecked checkbox arrays before validation to make sure that no values from session are taken.
		if ($this->currentStep > $this->lastStep) {
			$currentGP = $this->utilityFuncs->getMergedGP();
			if ($this->settings['checkBoxFields']) {
				$checkBoxFields = $this->utilityFuncs->getSingle($this->settings, 'checkBoxFields');
				$fields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $checkBoxFields);
				foreach ($fields as $idx => $field) {
					if(isset($this->gp[$field]) && !isset($currentGP[$field])) {
						unset($this->gp[$field]);
					}
				}
			}
			$this->globals->setGP($this->gp);
		}

		//Parse conditions again. An interceptor might have added additional values.
		$this->parseConditions();

		if ($this->currentStep > $this->lastStep) {
			$this->loadSettingsForStep($this->lastStep);
		} else {
			$this->loadSettingsForStep($this->currentStep);
		}

		$this->globals->setRandomID($this->gp['randomID']);

		//run validation
		$this->errors = array();
		$valid = array(TRUE);
		if ($this->currentStep >= $this->lastStep) {
			$this->validateErrorCheckConfig();
		}
		if (isset($this->settings['validators.']) && 
			is_array($this->settings['validators.']) && 
			intval($this->utilityFuncs->getSingle($this->settings['validators.'], 'disable')) !== 1) {

			foreach ($this->settings['validators.'] as $idx => $tsConfig) {
				if ($idx !== 'disable') {
					$className = $this->utilityFuncs->getPreparedClassName($tsConfig);
					if (is_array($tsConfig) && strlen($className) > 0) {
						if (intval($this->utilityFuncs->getSingle($tsConfig, 'disable')) !== 1) {

							$validator = $this->componentManager->getComponent($className);
							if ($this->currentStep === $this->lastStep) {
								$userSetting = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->utilityFuncs->getSingle($tsConfig['config.'], 'restrictErrorChecks'));
								$autoSetting = array(
									'fileAllowedTypes',
									'fileRequired',
									'fileMaxCount',
									'fileMinCount',
									'fileMaxSize',
									'fileMinSize',
									'fileMaxTotalSize'
								);
								$merged = array_merge($userSetting, $autoSetting);
								$tsConfig['config.']['restrictErrorChecks'] = implode(',', $merged);
								unset($tsConfig['config.']['restrictErrorChecks.']);
							}
							$tsConfig['config.'] = $this->addDefaultComponentConfig($tsConfig['config.']);
							$validator->init($this->gp, $tsConfig['config.']);
							$validator->validateConfig();
							$res = $validator->validate($this->errors);
							array_push($valid, $res);
						}
					} else {
						$this->utilityFuncs->throwException('classesarray_error');
					}
				}
			}
		}

		//process files
		if ($this->currentStep >= $this->lastStep) {
			$this->processFiles();
		}

		//if form is valid
		if ($this->isValid($valid)) {

			$this->loadSettingsForStep($this->currentStep);
			$this->parseConditions();

			//read template file
			$this->templateFile = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings);
			$this->globals->setTemplateCode($this->templateFile);
			$this->langFiles = $this->utilityFuncs->readLanguageFiles($this->langFiles, $this->settings);
			$this->globals->setLangFiles($this->langFiles);

			$this->view->setLangFiles($this->langFiles);
			$this->view->setSettings($this->settings);
			$this->setViewSubpart($this->currentStep);

			$this->storeGPinSession();
			$this->mergeGPWithSession();

				//mark step as finished
			$finishedSteps = $this->globals->getSession()->get('finishedSteps');
			if(!is_array($finishedSteps)) {
				$finishedSteps = array();
			}

			if($this->currentStep > $this->lastStep && !in_array($this->currentStep - 1, $finishedSteps)) {
				$finishedSteps[] = $this->currentStep - 1;
			}
			$this->globals->getSession()->set('finishedSteps', $finishedSteps);

			//if no more steps
			if ($this->finished) {
				return $this->processFinished();
			} else {
				return $this->view->render($this->gp, $this->errors);
			}
		} else {

			$this->templateFile = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings);
			$this->globals->setTemplateCode($this->templateFile);
			$this->langFiles = $this->utilityFuncs->readLanguageFiles($this->langFiles, $this->settings);
			$this->globals->setLangFiles($this->langFiles);

			$this->view->setLangFiles($this->langFiles);
			$this->view->setSettings($this->settings);
			$this->setViewSubpart($this->currentStep);
			return $this->processNotValid();
		}
	}

	/**
	 * Validate if the error checks have all been set correctly.
	 *
	 * @return void
	 */
	protected function validateErrorCheckConfig() {
		if (isset($_FILES) && is_array($_FILES) && !empty($_FILES)) {

			//for all file properties
			foreach ($_FILES as $sthg => $files) {

				//if a file upload field exists
				if (isset($files['name']) && is_array($files['name'])) {

					//for all file names
					$uploadFields = array_keys($files['name']);
					foreach ($uploadFields as $field) {

						//if a file was uploaded through this field
						if(!is_array($files['tmp_name'][$field])) {
							$files['tmp_name'][$field] = array($files['tmp_name'][$field]);
						}
						if(count($files['tmp_name'][$field]) > 0) {
							$valid = FALSE;
							$hasAllowedTypesCheck = FALSE;
							if (isset($this->settings['validators.']) && 
								is_array($this->settings['validators.']) && 
								intval($this->utilityFuncs->getSingle($this->settings['validators.'], 'disable')) !== 1) {

								foreach ($this->settings['validators.'] as $idx => $tsConfig) {
									if($tsConfig['config.']['fieldConf.'][$field . '.']['errorCheck.']) {
										foreach($tsConfig['config.']['fieldConf.'][$field . '.']['errorCheck.'] as $errorCheck) {
											if($errorCheck === 'fileAllowedTypes') {
												$hasAllowedTypesCheck = TRUE;
											}
										}
									}
								}
							}
							if($hasAllowedTypesCheck) {
								$valid = TRUE;
							} else {
								$missingChecks = array();
								if(!$hasAllowedTypesCheck) {
									$missingChecks[] = 'fileAllowedTypes';
								}
								$this->utilityFuncs->throwException('error_checks_missing', implode(',', $missingChecks), $field);
							}
						}
					}
				}
			}
		}
	}

	/**
	 * Process a form containing errors.
	 *
	 * @return Rendered form
	 */
	protected function processNotValid() {
		$this->gp['formErrors'] = $this->errors;
		$this->globals->setGP($this->gp);

		//stay on current step
		if ($this->lastStep < $this->globals->getSession()->get('currentStep')) {
			$this->globals->getSession()->set('currentStep', $this->lastStep);
			$this->currentStep = $this->lastStep;
		}

		//load settings from last step again because an error occurred
		$this->loadSettingsForStep($this->currentStep);
		$this->globals->getSession()->set('settings', $this->settings);

		//read template file
		$this->templateFile = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings);
		$this->globals->setTemplateCode($this->templateFile);
		$this->langFiles = $this->utilityFuncs->readLanguageFiles($this->langFiles, $this->settings);
		$this->globals->setLangFiles($this->langFiles);

		$this->view->setLangFiles($this->langFiles);
		$this->view->setSettings($this->settings);

		//reset the template because step had probably been decreased
		$this->setViewSubpart($this->currentStep);
		
		if ($this->currentStep >= $this->lastStep) {
			$this->storeGPinSession();
			$this->mergeGPWithSession();
		}

		return $this->view->render($this->gp, $this->errors);
	}

	/**
	 * Process a form containing no more steps (a form which is finished)
	 *
	 * @return Output of a Finisher
	 */
	protected function processFinished() {

		//If skipView is set, call preProcessors and initInterceptors here
		if (intval($this->utilityFuncs->getSingle($this->settings, 'skipView')) === 1) {

			//run preProcessors
			$output = $this->runClasses($this->settings['preProcessors.']);
			if (strlen($output) > 0) {
				return $output;
			}

			//run init interceptors
			$this->addFormhandlerClass($this->settings['initInterceptors.'], 'Interceptor_Filtreatment');
			$output = $this->runClasses($this->settings['initInterceptors.']);
			if (strlen($output) > 0) {
				return $output;
			}
		}
		$this->storeSettingsInSession();

		//run save interceptors
		$this->addFormhandlerClass($this->settings['saveInterceptors.'], 'Interceptor_Filtreatment');
		$output = $this->runClasses($this->settings['saveInterceptors.']);
		if (strlen($output) > 0) {
			return $output;
		}

		//run loggers
		$this->addFormhandlerClass($this->settings['loggers.'], 'Logger_DB');
		$output = $this->runClasses($this->settings['loggers.']);
		if (strlen($output) > 0) {
			return $output;
		}

		//run finishers
		if (isset($this->settings['finishers.']) && is_array($this->settings['finishers.']) && intval($this->utilityFuncs->getSingle($this->settings['finishers.'], 'disable')) !== 1) {
			ksort($this->settings['finishers.']);

			foreach ($this->settings['finishers.'] as $idx => $tsConfig) {
				if ($idx !== 'disabled') {
					$className = $this->utilityFuncs->getPreparedClassName($tsConfig);
					if (is_array($tsConfig) && strlen($className) > 0) {
						if (intval($this->utilityFuncs->getSingle($tsConfig, 'disable')) !== 1) {

							$finisher = $this->componentManager->getComponent($className);
							$tsConfig['config.'] = $this->addDefaultComponentConfig($tsConfig['config.']);
							$finisher->init($this->gp, $tsConfig['config.']);
							$finisher->validateConfig();

							//if the finisher returns HTML (e.g. Tx_Formhandler_Finisher_SubmittedOK)
							if (intval($this->utilityFuncs->getSingle($tsConfig['config.'], 'returns')) === 1) {
								$this->globals->getSession()->set('finished', TRUE);
								return $finisher->process();
							} else {
								$this->gp = $finisher->process();
								$this->globals->setGP($this->gp);
							}
						}
					} else {
						$this->utilityFuncs->throwException('classesarray_error');
					}
				}
			}
			$this->globals->getSession()->set('finished', TRUE);
		}
	}

	/**
	 * Process a form which has not been submitted.
	 *
	 * @return Rendered form
	 */
	protected function processNotSubmitted() {
		$this->loadSettingsForStep($this->currentStep);
		$this->parseConditions();

		$this->view->setSettings($this->settings);

		$this->templateFile = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings);
		$this->globals->setTemplateCode($this->templateFile);
		$this->langFiles = $this->utilityFuncs->readLanguageFiles($this->langFiles, $this->settings);
		$this->globals->setLangFiles($this->langFiles);

		$this->view->setLangFiles($this->langFiles);
		$this->setViewSubpart($this->currentStep);

		$output = $this->runClasses($this->settings['preProcessors.']);
		if (strlen($output) > 0) {
			return $output;
		}

		$this->addFormhandlerClass($this->settings['initInterceptors.'], 'Interceptor_Filtreatment');
		$output = $this->runClasses($this->settings['initInterceptors.']);
		if (strlen($output) > 0) {
			return $output;
		}

		//Parse conditions again. An interceptor might have added additional values.
		$this->parseConditions();
		$this->loadSettingsForStep($this->currentStep);

		return $this->view->render($this->gp, $this->errors);
	}

	/**
	 * Stores file names of uploaded files into the internal GET/POST parameters storage ($this->gp) so that they can be used later on in "value markers", userFuncs, ...
	 *
	 * @return void
	 */
	protected function storeFileNamesInGP() {

		//put file names into $this->gp
		$sessionFiles = $this->globals->getSession()->get('files');
		if (!is_array($sessionFiles)) {
			$sessionFiles = array();
		}
		foreach ($sessionFiles as $fieldname => $files) {
			$fileNames = array();
			if (is_array($files)) {
				foreach ($files as $idx => $fileInfo) {
					$fileName = $fileInfo['uploaded_name'];
					if (!$fileName) {
						$fileName = $fileInfo['name'];
					}
					$fileNames[] = $fileName;
				}
			}
			$this->gp[$fieldname] = implode(',', $fileNames);
		}
	}

	/**
	 * Adds default configuration for every Formhandler component to the given configuration array
	 *
	 * @param array $conf The configuration of the component set in TS
	 * @return array The initial configuration plus the default configuration
	 */
	protected function addDefaultComponentConfig($conf) {
		if (!$conf['langFiles']) {
			$conf['langFiles'] = $this->langFiles;
		}
		$conf['formValuesPrefix'] = $this->settings['formValuesPrefix'];
		$conf['templateSuffix'] = $this->settings['templateSuffix'];
		return $conf;
	}

	/**
	 * Adds a mandatory component to the classes array
	 *
	 * @return void
	 */
	protected function addFormhandlerClass(&$classesArray, $className){

		if (!isset($classesArray) && !is_array($classesArray)) {

			//add class to the end of the array
			$classesArray[] = array('class' => $className);
		} else {
			$found = FALSE;
			$className = $this->utilityFuncs->prepareClassName($className);
			foreach ($classesArray as $idx => $classOptions) {
				$currentClassName = $this->utilityFuncs->getPreparedClassName($classOptions);
				if ($className === $currentClassName) {
					$found = TRUE;
				}
			}
			if (!$found) {

				//add class to the end of the array
				$classesArray[] = array('class' => $className);
			}
		}
	}

	
	/**
	 * Removes files from the internal file storage
	 *
	 * @return void
	 */
	protected function processFileRemoval() {
		if ($this->gp['removeFile']) {
			$filename = $this->gp['removeFile'];
			$fieldname = $this->gp['removeFileField'];
			$sessionFiles = $this->globals->getSession()->get('files');
			if (is_array($sessionFiles)) {

				foreach ($sessionFiles as $field => $files) {
					if (!strcmp($field, $fieldname)) {

						//get upload folder
						$uploadFolder = $this->utilityFuncs->getTempUploadFolder($field);

						//build absolute path to upload folder
						$uploadPath = $this->utilityFuncs->getTYPO3Root() . $uploadFolder;
						$found = FALSE;
						foreach ($files as $key => $fileInfo) {
							if (!strcmp($fileInfo['uploaded_name'], $filename)) {
								$found = TRUE;
								unset($sessionFiles[$field][$key]);
								if(file_exists($uploadPath . $fileInfo['uploaded_name'])) {
									unlink($uploadPath . $fileInfo['uploaded_name']);
								}
							}
						}
						if (!$found) {
							foreach ($files as $key => $fileInfo) {
								if (!strcmp($fileInfo['name'], $filename)) {
									unset($sessionFiles[$field][$key]);
									if(file_exists($uploadPath . $fileInfo['name'])) {
										unlink($uploadPath . $fileInfo['name']);
									}
								}
							}
						}
					}
				}
			}
			unset($this->gp['removeFile']);
			unset($this->gp['removeFileField']);
			$this->globals->getSession()->set('files', $sessionFiles);
		}
	}

	/**
	 * Processes uploaded files, moves them to a temporary upload folder, renames them if they already exist and
	 * stores the information in user session
	 *
	 * @return void
	 */
	protected function processFiles() {
		$sessionFiles = $this->globals->getSession()->get('files');
		$tempFiles = $sessionFiles;

		if (isset($_FILES) && is_array($_FILES) && !empty($_FILES)) {

			$uploadedFilesWithSameNameAction = $this->utilityFuncs->getSingle($this->settings['files.'], 'uploadedFilesWithSameName');
			if(!$uploadedFilesWithSameNameAction) {
				$uploadedFilesWithSameNameAction = 'ignore';
			}

			//for all file properties
			foreach ($_FILES as $sthg => $files) {

				//if a file was uploaded
				if (isset($files['name']) && is_array($files['name'])) {

					//for all file names
					foreach ($files['name'] as $field => $uploadedFiles) {

						//If only a single file is uploaded
						if(!is_array($uploadedFiles)) {
							$uploadedFiles = array($uploadedFiles);
						}

						if (!isset($this->errors[$field])) {

							//get upload folder
							$uploadFolder = $this->utilityFuncs->getTempUploadFolder($field);

							//build absolute path to upload folder
							$uploadPath = $this->utilityFuncs->getTYPO3Root() . $uploadFolder;

							if (!file_exists($uploadPath)) {
								$this->utilityFuncs->debugMessage('folder_doesnt_exist', array($uploadPath), 3);
								return;
							}

							foreach($uploadedFiles as $idx => $name) {
								$exists = FALSE;
								if (is_array($sessionFiles[$field])) {
									foreach ($sessionFiles[$field] as $fileId => $fileOptions) {
										if ($fileOptions['name'] === $name) {
											$exists = TRUE;
										}
									}
								}
								if (!$exists || $uploadedFilesWithSameNameAction === 'replace' || $uploadedFilesWithSameNameAction === 'append') {
									$name = $this->utilityFuncs->doFileNameReplace($name);
									$filename = substr($name, 0, strpos($name, '.'));
									if (strlen($filename) > 0) {
										$ext = substr($name, strpos($name, '.'));
										$suffix = 1;
	
										//build file name
										$uploadedFileName = $filename . $ext;
	
										if($uploadedFilesWithSameNameAction !== 'replace') {
	
											//rename if exists
											while(file_exists($uploadPath . $uploadedFileName)) {
												$uploadedFileName = $filename . '_' . $suffix . $ext;
												$suffix++;
											}
										}
										$files['name'][$field][$idx] = $uploadedFileName;
	
										//move from temp folder to temp upload folder
										if(!is_array($files['tmp_name'][$field])) {
											$files['tmp_name'][$field] = array($files['tmp_name'][$field]);
										}
										move_uploaded_file($files['tmp_name'][$field][$idx], $uploadPath . $uploadedFileName);
										\TYPO3\CMS\Core\Utility\GeneralUtility::fixPermissions($uploadPath . $uploadedFileName);
										$files['uploaded_name'][$field][$idx] = $uploadedFileName;
	
										//set values for session
										$tmp['name'] = $name;
										$tmp['uploaded_name'] = $uploadedFileName;
										$tmp['uploaded_path'] = $uploadPath;
										$tmp['uploaded_folder'] = $uploadFolder;
										$uploadedUrl = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . $uploadFolder . $uploadedFileName;
										$uploadedUrl = str_replace('//', '/', $uploadedUrl);
										$tmp['uploaded_url'] = $uploadedUrl;
										$tmp['size'] = $files['size'][$field][$idx];
										if(is_array($files['type'][$field][$idx])) {
											$tmp['type'] = $files['type'][$field][$idx];
										} else {
											$tmp['type'] = $files['type'][$field];
										}
										if (!is_array($tempFiles[$field]) && strlen($field) > 0) {
											$tempFiles[$field] = array();
										}
										if(!$exists || $uploadedFilesWithSameNameAction !== 'replace') {
											array_push($tempFiles[$field], $tmp);
										}
										if (!is_array($this->gp[$field])) {
											$this->gp[$field] = array();
										}
										if(!$exists || $uploadedFilesWithSameNameAction !== 'replace') {
											array_push($this->gp[$field], $uploadedFileName);
										}
									}
								}
							}
						}
					}
				}
			}
		}
		$this->globals->getSession()->set('files', $tempFiles);
		$this->utilityFuncs->debugMessage('Files:', array(), 1, (array)$tempFiles);
	}

	/**
	 * Stores the current GET/POST parameters in SESSION
	 *
	 * @param array &$settings Reference to the settings array to get information about checkboxes and radiobuttons.
	 * @return void
	 */
	protected function storeGPinSession() {
		if ($this->currentStep > $this->lastStep) {
			$this->loadSettingsForStep($this->lastStep);
		}
		$newGP = $this->handleCheckBoxFields();
		if ($this->currentStep > $this->lastStep) {
			$this->loadSettingsForStep($this->currentStep);
		}
		$data = $this->globals->getSession()->get('values');
		
		$checkBoxFields = $this->utilityFuncs->getSingle($this->settings, 'checkBoxFields');
		$checkBoxFields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $checkBoxFields);

		//set the variables in session
		if ($this->lastStep !== $this->currentStep) {
			foreach ($newGP as $key => $value) {
				if (!strstr($key, 'step-') && $key !== 'submitted' && $key !== 'randomID' && 
					$key !== 'removeFile' && $key !== 'removeFileField' && $key !== 'submitField') {

					$data[$this->lastStep][$key] = $newGP[$key];
				}
			}
		}

		//Search for checkboxes which were unchecked in this step.
		foreach($checkBoxFields as $field) {
			if(!isset($newGP[$field])) {
				unset($data[$this->lastStep][$field]);
			}
		}
		$this->globals->getSession()->set('values', $data);
	}

	/**
	 * Resets the values in session to have a clean form
	 *
	 * @return void
	 */
	protected function reset($gp = array()) {
		$values = array (
			'creationTstamp' => time(),
			'values' => NULL,
			'files' => NULL,
			'lastStep' => NULL,
			'currentStep' => 1,
			'startblock' => NULL,
			'endblock' => NULL,
			'inserted_uid' => NULL,
			'inserted_tstamp' => NULL,
			'key_hash' => NULL,
			'finished' => NULL,
			'finishedSteps' => array()
		);
		$this->globals->getSession()->setMultiple($values);
		$this->gp = $gp;
		$this->currentStep = 1;
		$this->globals->setGP($this->gp);
		$this->utilityFuncs->debugMessage('cleared_session');
	}

	/**
	 * Searches for current step and sets $this->currentStep according
	 *
	 * @return void
	 */
	protected function findCurrentStep() {
		if (isset($this->gp) && is_array($this->gp)) {
			$action = 'reload';
			$keys = array_keys($this->gp);
			foreach ($keys as $idx => $pname) {
				if (strstr($pname, 'step-')) {
					preg_match_all('/step-([0-9]+)-([a-z]+)/', $pname, $matches);
					if (isset($matches[2][0])) {
						$action = $matches[2][0];
						$step = intval($matches[1][0]);
					}
				}
			}
		}

		$allowStepJumps = FALSE;
		if(isset($this->settings['allowStepJumps'])) {
			$allowStepJumps = (bool)$this->utilityFuncs->getSingle($this->settings, 'allowStepJumps');
		}
		$stepInSession = max(intval($this->globals->getSession()->get('currentStep')), 1);
		switch ($action) {
			case 'prev':
			case 'next':
				if ($step > $stepInSession) {
					if($allowStepJumps) {
						$this->currentStep = $step;
					} else {
						$this->currentStep = $stepInSession + 1;
					}
				} elseif ($step < $stepInSession) {
					if($allowStepJumps) {
						$this->currentStep = $step;
					} else {
						$this->currentStep = $stepInSession - 1;
					}
				} else {
					$this->currentStep = $step;
				}
				break;
			default:
				$this->currentStep = $stepInSession;
				break;
		}
		if ($this->currentStep < 1) {
			$this->currentStep = 1;
		}
		if (!$this->currentStep) {
			$this->currentStep = 1;
		}

		$isValidStep = TRUE;
		$disableStepCheck = FALSE;
		if(isset($this->settings['disableStepCheck'])) {
			$disableStepCheck = (bool)$this->utilityFuncs->getSingle($this->settings, 'disableStepCheck');
		}
		if(!$disableStepCheck) {
			for($i = 1; $i < $this->currentStep - 1; $i++) {
				$finishedSteps = $this->globals->getSession()->get('finishedSteps');
				if(is_array($finishedSteps) && !in_array($i, $finishedSteps)) {
					$isValidStep = FALSE;
				}
			}
		}
		$this->utilityFuncs->debugMessage('current_step', array($this->currentStep));

		if(!$isValidStep) {
			$this->utilityFuncs->throwException('You are not allowed to go to this step!');
		}
	}

	/**
	 * Validates the Formhandler config.
	 * E.g. If email addresses were set in flexform then Finisher_Mail must exist in the TS configuration.
	 *
	 * @return void
	 */
	public function validateConfig() {
		$options = array(
			array('to_email', 'sEMAILADMIN', 'finishers', 'Tx_Formhandler_Finisher_Mail'),
			array('to_email', 'sEMAILUSER', 'finishers', 'Tx_Formhandler_Finisher_Mail'),
			array('redirect_page', 'sMISC', 'finishers', 'Tx_Formhandler_Finisher_Redirect'),
			array('required_fields', 'sMISC', 'validators', 'Tx_Formhandler_Validator_Default'),
		);
		foreach ($options as $idx => $option) {
			$fieldName = $option[0];
			$flexformSection = $option[1];
			$component = $option[2];
			$componentName = $option[3];
			$value = $this->utilityFuncs->pi_getFFvalue($this->cObj->data['pi_flexform'], $fieldName, $flexformSection);

			// Check if a Mail Finisher can be found in the config
			$isConfigOk = FALSE;
			if (is_array($this->settings[$component . '.'])) {
				foreach ($this->settings[$component . '.'] as $idx => $finisher) {
					$className = $this->utilityFuncs->getPreparedClassName($finisher);
					if ($className == $componentName || @is_subclass_of($className, $componentName)) {

						$isConfigOk = TRUE;
						break;
					}
				}
			}

			if ($value != '' && !$isConfigOk) {
				$this->utilityFuncs->throwException('missing_component', $component, $value, $componentName);
			}
		}
	}

	/**
	 * Method to parse a conditions block of the TS setting "if"
	 *
	 * @param array $settings The settings of this form
	 * @return void
	 */
	protected function parseConditionsBlock($settings) {
		$finalResult = FALSE;
		foreach ($settings['if.'] as $idx => $conditionSettings) {
			$conditions = $conditionSettings['conditions.'];
			$condition = '';
			$orConditions = array();
			foreach ($conditions as $subIdx => $andConditions) {
				$results = array();
				foreach ($andConditions as $subSubIdx => $andCondition) {
					if (strstr($andCondition, '!=')) {
						list($field, $value) = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('!=', $andCondition);
						$value = $this->utilityFuncs->parseOperand($value, $this->gp);
						$result = ($this->utilityFuncs->getGlobal($field, $this->gp) !== $value);
					} elseif (strstr($andCondition, '=')) {
						list($field, $value) = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('=', $andCondition);
						$value = $this->utilityFuncs->parseOperand($value, $this->gp);
						$result = ($this->utilityFuncs->getGlobal($field, $this->gp) === $value);
					} elseif (strstr($andCondition, '>')) {
						list($field, $value) = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('>', $andCondition);
						$value = $this->utilityFuncs->parseOperand($value, $this->gp);
						$result = ($this->utilityFuncs->getGlobal($field, $this->gp) > $value);
					} elseif (strstr($andCondition, '<')) {
						list($field, $value) = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('<', $andCondition);
						$value = $this->utilityFuncs->parseOperand($value, $this->gp);
						$result = ($this->utilityFuncs->getGlobal($field, $this->gp) < $value);
					} else {
						$field = $andCondition;
						$keys = explode('|', $field);
						$numberOfLevels = count($keys);
						$rootKey = trim($keys[0]);
						$value = $this->gp[$rootKey];

						$result = (isset($this->gp[$rootKey]) && !empty($this->gp[$rootKey]));
						for ($i = 1; $i < $numberOfLevels && isset($value); $i++) {
							$currentKey = trim($keys[$i]);
							if (is_object($value)) {
								$value = $value->$currentKey;
								$result = (isset($value->$currentKey) && !empty($value->$currentKey));
							} elseif (is_array($value)) {
								$value = $value[$currentKey];
								$result = (isset($value[$currentKey]) && !empty($value[$currentKey]));
							} else {
								$result = FALSE;
							}
						}
					}
					$results[] = ($result ? 'TRUE' : 'FALSE');
				}
				$orConditions[] = '(' . implode(' && ', $results) . ')';
			}
			$finalCondition = '(' . implode(' || ', $orConditions) . ')';

			eval('$evaluation = ' . $finalCondition . ';');

			if ($evaluation) {
				$newSettings = $conditionSettings['isTrue.'];
				if (is_array($newSettings)) {
					$this->settings = $this->utilityFuncs->mergeConfiguration($this->settings, $newSettings);
				}
			} else {
				$newSettings = $conditionSettings['else.'];
				if (is_array($newSettings)) {
					$this->settings = $this->utilityFuncs->mergeConfiguration($this->settings, $newSettings);
				}
			}
		
		}
	}

	/**
	 * Method to parse all conditions set in the TS setting "if"
	 *
	 * @return void
	 */
	protected function parseConditions() {

		//parse global conditions
		if (is_array($this->settings['if.'])) {
			$this->parseConditionsBlock($this->settings);
		}

		//parse conditions for each of the previous steps
		$endStep = $this->globals->getSession()->get('currentStep');
		$step = 1;

		while($step <= $endStep) {
			$stepSettings = $this->settings[$step . '.'];
			if (is_array($stepSettings['if.'])) {
				$this->parseConditionsBlock($stepSettings);
			}
			$step++;
		}
	}

	/**
	 * Init method for the controller.
	 * This method sets internal values, initializes the ajax handler and the session.
	 *
	 * @return void
	 */
	protected function init() {

		$this->settings = $this->getSettings();
		$this->formValuesPrefix = $this->utilityFuncs->getSingle($this->settings, 'formValuesPrefix');
		$this->globals->setFormID($this->utilityFuncs->getSingle($this->settings, 'formID'));
		$this->globals->setFormValuesPrefix($this->formValuesPrefix);

		$isDebugMode = $this->utilityFuncs->getSingle($this->settings, 'debug');
		$this->debugMode = (intval($isDebugMode) === 1);

		$this->gp = $this->utilityFuncs->getMergedGP();

		$randomID = $this->gp['randomID'];
		if (!$randomID) {
			if($this->settings['uniqueFormID']) {
				$randomID = $this->utilityFuncs->getSingle($this->settings, 'uniqueFormID');
			} else {
				$randomID = $this->utilityFuncs->generateRandomID();
			}
		}
		$this->globals->setRandomID($randomID);

		$sessionClass = $this->utilityFuncs->getPreparedClassName($this->settings['session.'], 'Session_PHP');
		$session = $this->componentManager->getComponent($sessionClass);
		$session->init($this->gp, $this->settings['session.']['config.']);
		$session->start();
		$this->globals->setSession($session);

		$action = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('action');
		if ($this->globals->getFormValuesPrefix()) {
			$temp = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP($this->globals->getFormValuesPrefix());
			$action = $temp['action'];
		}
		if($this->globals->getSession()->get('finished') && !$action) {
			$this->globals->getSession()->reset();
			unset($_GET[$this->globals->getFormValuesPrefix()]);
			unset($_GET['id']);
			$this->utilityFuncs->doRedirect($GLOBALS['TSFE']->id, FALSE, $_GET);
			exit();
		}
		$this->parseConditions();

		$this->initializeDebuggers();

		$this->getStepInformation();

		$currentStepFromSession = $this->globals->getSession()->get('currentStep');
		$prevStep = $currentStepFromSession;
		if (intval($prevStep) !== intval($currentStepFromSession)) {
			$this->currentStep = 1;
			$this->lastStep = 1;
			$this->utilityFuncs->throwException('You messed with the steps!');
		}

		$this->mergeGPWithSession();

		$this->parseConditions();

		if(intval($this->utilityFuncs->getSingle($this->settings, 'disableConfigValidation')) === 0) {
			$this->validateConfig();
		}
		$this->globals->setSettings($this->settings);

		//set debug mode again cause it may have changed in specific step settings
		$isDebugMode = $this->utilityFuncs->getSingle($this->settings, 'debug');
		$this->debugMode = (intval($isDebugMode) === 1);
		$this->globals->getSession()->set('debug', $this->debugMode);

		$this->utilityFuncs->debugMessage('using_prefix', array($this->formValuesPrefix));

		$this->globals->getSession()->set('predef', $this->globals->getPredef());

		//init view
		$viewClass = $this->utilityFuncs->getPreparedClassName($this->settings['view.'], 'View_Form');
		$this->utilityFuncs->debugMessage('using_view', array($viewClass));

		$this->utilityFuncs->debugMessage('current_gp', array(), 1, $this->gp);

		$this->storeSettingsInSession();

		$this->mergeGPWithSession();

		$this->submitted = $this->isFormSubmitted();

		$this->globals->setSubmitted($this->submitted);
		if ($this->globals->getSession()->get('creationTstamp') === NULL) {
			if($this->submitted) {
				$this->reset($this->gp);
				$this->findCurrentStep();
				$this->globals->getSession()->set('currentStep', $this->currentStep);
			} else {
				$this->reset();
			}
		}

		$this->addCSS();
		$this->addJS();
		$this->addJSFooter();

		$this->utilityFuncs->debugMessage('current_session_params', array(), 1, (array)$this->globals->getSession()->get('values'));
		$this->view = $this->componentManager->getComponent($viewClass);
		$this->view->setLangFiles($this->langFiles);
		$this->view->setSettings($this->settings);

		$this->globals->setGP($this->gp);

		//init ajax
		if ($this->settings['ajax.']) {
			$class = $this->utilityFuncs->getPreparedClassName($this->settings['ajax.'], 'AjaxHandler_JQuery');
			$this->utilityFuncs->debugMessage('using_ajax', array($class));
			$ajaxHandler = $this->componentManager->getComponent($class);
			$this->globals->setAjaxHandler($ajaxHandler);

			$ajaxHandler->init($this->settings['ajax.']['config.']);
			$ajaxHandler->initAjax();
		}
		if (!$this->gp['randomID']) {
			$this->gp['randomID'] = $this->globals->getRandomID();
		}
	}

	/**
	 * Checks if the form has been submitted
	 *
	 * @return boolean
	 */
	protected function isFormSubmitted() {
		$submitted = $this->gp['submitted'];
		if ($submitted) {
			foreach ($this->gp as $key => $value) {
				if (substr($key, 0, 5) === 'step-') {
					$submitted = TRUE;
				}
			}
		} elseif (intval($this->utilityFuncs->getSingle($this->settings, 'skipView')) === 1) {
			$submitted = TRUE;
		}

		return $submitted;
	}

	/**
	 * Sets the template of the view.
	 *
	 * @param int The current step
	 * @return void
	 */
	protected function setViewSubpart($step) {
		$this->finished = FALSE;

		if (intval($this->utilityFuncs->getSingle($this->settings, 'skipView')) === 1) {
			$this->finished = TRUE;
		} elseif (strstr($this->templateFile, ('###TEMPLATE_FORM' . $step . $this->settings['templateSuffix'] . '###'))) {

			// search for ###TEMPLATE_FORM[step][suffix]###
			$this->utilityFuncs->debugMessage('using_subpart', array('###TEMPLATE_FORM' . $step . $this->settings['templateSuffix'] . '###'));
			$this->view->setTemplate($this->templateFile, ('FORM' . $step . $this->settings['templateSuffix']));
		} elseif (!isset($this->settings['templateSuffix']) && strstr($this->templateFile, ('###TEMPLATE_FORM' . $step . '###'))) {

			//search for ###TEMPLATE_FORM[step]###
			$this->utilityFuncs->debugMessage('using_subpart', array('###TEMPLATE_FORM' . $step . '###'));
			$this->view->setTemplate($this->templateFile, ('FORM' . $step));

		} elseif (intval($step) === intval($this->globals->getSession()->get('lastStep')) + 1) {
			$this->finished = TRUE;
		}
	}

	/**
	 * Stores some settings of the form into the session
	 *
	 * @return void
	 */
	protected function storeSettingsInSession() {
		$values = array (
			'formValuesPrefix' => $this->formValuesPrefix,
			'settings' => $this->settings,
			'debug' => $this->debugMode,
			'currentStep' => $this->currentStep,
			'totalSteps' => $this->totalSteps,
			'lastStep' => $this->lastStep,
			'templateSuffix' => $this->settings['templateSuffix']
		);
		$this->globals->getSession()->setMultiple($values);
		$this->globals->setFormValuesPrefix($this->formValuesPrefix);
		$this->globals->setTemplateSuffix($this->settings['templateSuffix']);
	}

	/**
	 * Loads form settings for a given step
	 *
	 * @param int $step The step to load the settings for
	 * @return void
	 */
	protected function loadSettingsForStep($step) {

		//merge settings with specific settings for current step
		if (isset($this->settings[$step . '.']) && is_array($this->settings[$step . '.'])) {
			$this->settings = $this->utilityFuncs->mergeConfiguration($this->settings, $this->settings[$step . '.']);
		}
		$this->globals->getSession()->set('settings', $this->settings);
	}

	/**
	 * Sets the current and last step of the form
	 *
	 * @return void
	 */
	protected function getStepInformation() {

		$this->findCurrentStep();

		$this->lastStep = $this->globals->getSession()->get('currentStep');
		if (!$this->lastStep) {
			$this->lastStep = 1;
		}

		$this->templateFile = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings);

		//Parse all template files and search for step subparts to calculate total step count
		$allTemplateCodes = array();
		$step = 1;
		while(isset($this->settings[$step . '.']['templateFile'])) {
			$allTemplateCodes[] = $this->utilityFuncs->readTemplateFile($this->templateFile, $this->settings[$step . '.']);
			$step++;
		}

		$subparts = array();
		foreach($allTemplateCodes as $templateCode) {
			preg_match_all('/(###TEMPLATE_FORM)([0-9]+)(_.*)?(###)/', $templateCode, $matches);

			$subparts = array_merge($subparts, array_unique($matches[2]));
		}
		sort($subparts);
		$countSubparts = count($subparts);
		$this->totalSteps = $subparts[$countSubparts - 1];
		if ($this->totalSteps > $countSubparts) {
			$this->utilityFuncs->debugMessage('subparts_missing', array(implode(', ', $subparts)), 2);
		} else {
			$this->utilityFuncs->debugMessage('total_steps', array($this->totalSteps));
		}
	}

	/**
	 * Merges the current GET/POST parameters with the stored ones in SESSION
	 *
	 * @return void
	 */
	protected function mergeGPWithSession() {
		if (!is_array($this->gp)) {
			$this->gp = array();
		}
		$values = $this->globals->getSession()->get('values');
		if (!is_array($values)) {
			$values = array();
		}

		$maxStep = $this->currentStep;
		foreach ($values as $step => &$params) {
			if (is_array($params) && (!$maxStep || $step <= $maxStep)) {
				unset($params['submitted']);
				foreach ($params as $key => $value) {
					if (!isset($this->gp[$key])) {
						$this->gp[$key] = $value;
					}
				}
			}
		}
	}

	/**
	 * Runs the class by calling process() method.
	 *
	 * @param array $classesArray: the configuration array
	 * @return void
	 */
	protected function runClasses($classesArray) {
		$return = '';
		if (isset($classesArray) && is_array($classesArray) && intval($this->utilityFuncs->getSingle($classesArray, 'disable')) !== 1) {

			ksort($classesArray);

			//Load language files everytime before running a component. They may have been changed by previous components
			$this->langFiles = $this->utilityFuncs->readLanguageFiles($this->langFiles, $this->settings);
			$this->globals->setLangFiles($this->langFiles);
			foreach ($classesArray as $idx => $tsConfig) {
				if ($idx !== 'disable') {
					$className = $this->utilityFuncs->getPreparedClassName($tsConfig);
					if (is_array($tsConfig) && strlen($className) > 0) {
						if (intval($this->utilityFuncs->getSingle($tsConfig, 'disable')) !== 1) {

							$this->utilityFuncs->debugMessage('calling_class', array($className));
							$obj = $this->componentManager->getComponent($className);
							$tsConfig['config.'] = $this->addDefaultComponentConfig($tsConfig['config.']);
							$obj->init($this->gp, $tsConfig['config.']);
							$obj->validateConfig();
							$return = $obj->process();
							if (is_array($return)) {

								//return value is an array. Treat it as the probably modified get/post parameters
								$this->gp = $return;
								$this->globals->setGP($this->gp);
							} else {

								//return value is no array. treat this return value as output.
								return $return;
							}
						}
					} else {
						$this->utilityFuncs->throwException('classesarray_error');
					}
				}
			}
		}
	}

	/**
	 * Read stylesheet file(s) set in TypoScript. If set add to header data
	 *
	 * @return void
	 */
	protected function addCSS() {
		$cssFiles = $this->utilityFuncs->parseResourceFiles($this->settings, 'cssFile');
		foreach ($cssFiles as $idx => $fileOptions) {
			$file = $fileOptions['file'];
			if(strlen(trim($file)) > 0) {
				$file = $this->utilityFuncs->resolveRelPathFromSiteRoot($file);
				if(file_exists($file)) {
					$pageRenderer = $GLOBALS['TSFE']->getPageRenderer();
					$pageRenderer->addCssFile(
						$file,
						$fileOptions['alternate'] ? 'alternate stylesheet' : 'stylesheet',
						$fileOptions['media'] ? $fileOptions['media'] : 'all',
						$fileOptions['title'] ? $fileOptions['title'] : '',
						empty($fileOptions['disableCompression']),
						$fileOptions['forceOnTop'] ? TRUE : FALSE,
						$fileOptions['allWrap'],
						$fileOptions['excludeFromConcatenation'] ? TRUE : FALSE
					);
				}
			}
		}
	}

	/**
	 * Read JavaScript file(s) set in TypoScript. If set add to header data
	 *
	 * @return void
	 */
	protected function addJS() {
		$jsFiles = $this->utilityFuncs->parseResourceFiles($this->settings, 'jsFile');
		foreach ($jsFiles as $idx => $fileOptions) {
			$file = $fileOptions['file'];
			if(strlen(trim($file)) > 0) {
				$file = $this->utilityFuncs->resolveRelPathFromSiteRoot($file);
				if(file_exists($file)) {
					$pageRenderer = $GLOBALS['TSFE']->getPageRenderer();
					$pageRenderer->addJsFile(
						$file,
						$fileOptions['type'] ? $fileOptions['type'] : 'text/javascript',
						empty($fileOptions['disableCompression']),
						$fileOptions['forceOnTop'] ? TRUE : FALSE,
						$fileOptions['allWrap'],
						$fileOptions['excludeFromConcatenation'] ? TRUE : FALSE
					);
				}
			}
		}
	}

	/**
	 * Read JavaScript file(s) set in TypoScript. If set add to footer data
	 *
	 * @return void
	 */
	protected function addJSFooter() {
		$jsFiles = $this->utilityFuncs->parseResourceFiles($this->settings, 'jsFileFooter');
		foreach ($jsFiles as $idx => $fileOptions) {
			$file = $fileOptions['file'];
			if(strlen(trim($file)) > 0) {
				$file = $this->utilityFuncs->resolveRelPathFromSiteRoot($file);
				if(file_exists($file)) {
					$pageRenderer = $GLOBALS['TSFE']->getPageRenderer();
					$pageRenderer->addJsFile(
						$file,
						$fileOptions['type'] ? $fileOptions['type'] : 'text/javascript',
						empty($fileOptions['disableCompression']),
						$fileOptions['forceOnTop'] ? TRUE : FALSE,
						$fileOptions['allWrap'],
						$fileOptions['excludeFromConcatenation'] ? TRUE : FALSE
					);
				}
			}
		}
	}

	/**
	 * Find out if submitted form was valid. If one of the values in the given array $valid is FALSE the submission was not valid.
	 *
	 * @param $validArr Array with the return values of each validator
	 * @return boolean
	 */
	protected function isValid($validArr) {
		$valid = TRUE;
		if (is_array($validArr)) {
			foreach ($validArr as $idx => $item) {
				if (!$item) {
					$valid = FALSE;
				}
			}
		}
		return $valid;
	}

	/**
	 * Checks if there are checkbox fields configured for this step.
	 * If found, Formhandler sets the correct value of the field(s)
	 *
	 * @return void
	 */
	protected function handleCheckBoxFields() {
		$newGP = $this->utilityFuncs->getMergedGP();

		//check for checkbox fields using the values in $newGP
		if ($this->settings['checkBoxFields']) {
			$checkBoxFields = $this->utilityFuncs->getSingle($this->settings, 'checkBoxFields');
			$fields = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $checkBoxFields);
			foreach ($fields as $idx => $field) {
				if (!isset($newGP[$field]) && isset($this->gp[$field]) && $this->lastStep < $this->currentStep) {
					$this->gp[$field] = $newGP[$field] = array();

				//Insert default checkbox values
				} elseif(!isset($newGP[$field]) && $this->lastStep < $this->currentStep) {
					if(is_array($this->settings['checkBoxUncheckedValue.']) && isset($this->settings['checkBoxUncheckedValue.'][$field])) {
						$this->gp[$field] = $newGP[$field] = $this->utilityFuncs->getSingle($this->settings['checkBoxUncheckedValue.'], $field);
					} elseif(isset($this->settings['checkBoxUncheckedValue'])) {
						$this->gp[$field] = $newGP[$field] = $this->utilityFuncs->getSingle($this->settings, 'checkBoxUncheckedValue');
					}
				}
			}
		}
		return $newGP;
	}

	/**
	 * Initializes the debuggers set in TS.
	 *
	 * @return void
	 */
	protected function initializeDebuggers() {
		$this->addFormhandlerClass($this->settings['debuggers.'], 'Debugger_Print');

		foreach ($this->settings['debuggers.'] as $idx => $options) {
			if(intval($this->utilityFuncs->getSingle($options, 'disable')) !== 1) {
				$debuggerClass = $this->utilityFuncs->getPreparedClassName($options);
				$debugger = $this->componentManager->getComponent($debuggerClass);
				$debugger->init($this->gp, $options['config.']);
				$debugger->validateConfig();
				$this->globals->addDebugger($debugger);
			}
		}
	}

}
?>